import json, socket
from toollib.guid import SnowFlake
from django.core.paginator import Paginator
from django.core.serializers.json import DjangoJSONEncoder

"""
查询本机ip地址
"""
def get_host_ip():
    try:
        s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
        s.connect(('8.8.8.8',80))
        ip=s.getsockname()[0]
    finally:
        s.close()
    return ip

'''
返回请求者ip
:param request: HTTPRequest对象
'''
def get_client_ip(request):
    if request.META.get('HTTP_X_FORWARDED_FOR'):
        return request.META['HTTP_X_FORWARDED_FOR']
    else:
        return request.META['REMOTE_ADDR']

"""
封装返回数据

:param code: 状态码
:param msg:  描述
:param data: 数据体
"""
def responseData(code, msg, data=''):
    data_ = {
        "code": code,
        "msg": msg,
        "data": data
    }
    return data_

'''
返回成功信息
:param data: 数据体
'''
def responseSuccess(data=None):
    return responseData(0, '操作成功', data)

'''
返回错误信息
:param msg: 错误信息
'''
def responseError(msg=None):
    return responseData(-1, msg)

"""
验证错误信息汇总到列表中返回

:param errors: 包含了验证错误信息的字典。Serializer实例对象的errors属性返回值
"""
def validateError(errors):
    errs = []
    for k,v in errors.items():
        err = v[0].title()
        if 'non_field_errors' != k:
            err = k + err
        errs.append(err)
    return errs

# 生成唯一随机数
def primaryKey():
    return SnowFlake().gen_uid()

"""
分页器

:param objs: 模型QuerySet对象
:param kwarg:   包含current、size的字典
"""
class MyPaginator:
    def __init__(self, objs, **kwarg):
        self.current = kwarg.get('current', 1)
        self.size = int(kwarg.get('size', 10))
        self.paginator = Paginator(objs, self.size)
    
    # 当前分页对象
    @property
    def page(self):
        return self.paginator.get_page(self.current)
    
    # 当前页数据
    @property
    def object_list(self):
        return self.page.object_list

    # 返回数据
    def data(self, records):
        return {
            "records": records,
            "total": self.paginator.count,
            "size": self.size,
            "current": self.page.number,
            "previousPage": self.page.previous_page_number() if self.page.has_previous() else 0,
            "nextPage": self.page.next_page_number() if self.page.has_next() else 0,
            "pages": self.paginator.num_pages
        }

"""
过滤字典中非模型字段的参数

:param model:           模型类对象
:param obj:             被过滤查询数据字典
:param kwargs.allow:    允许的字段名序列，默认为模型中字段列表
:param kwargs.exclude:  排除的字段列表
:param kwargs.icontains:不忽略大小写的包含匹配字段列表
:param kwargs.int:      需要转int类型的字段列表
:param kwargs.null:     查询为空的字段列表
:returns:               过滤后的字段字典
"""
def filterFields(model, obj, **kwargs):
    fields = [*map(lambda i:i.name, model._meta.get_fields())]     # 模型中所有字段
    fields = list(set(fields) - set(kwargs.get('exclude',[])))     # 过滤字段
    fields += kwargs.get('allow',[])
    # 过滤值为None、''的字段
    dic = []
    for k,v in obj.items():
        if v not in [None,''] and k in fields:
            if k in kwargs.get('icontains',[]): # 拼接成"xx__icontains"不忽略大小写的包含匹配
                k = k + '__icontains'
            if k in kwargs.get('int',[]):   # 值转int类型
                v = int(v)
            if k in kwargs.pop('null',[]):  # 拼接成"xxx__isnull"查询为空
                k = f"{k}__isnull"
                v = True
            dic.append((k,v))
    return dict(dic)

"""
Serializer实例转JSON对象

:param serializers: Serializer实例对象
:returns: 返回JSON对象
"""
def serializerJSON(serializers):
    return json.loads(json.dumps(list(serializers.data), cls=DjangoJSONEncoder, ensure_ascii=False))

'''
Serializer序列/反序列化类专用装饰器，将表单中空字符串替换成None。
注意：当模型字段是非None，且有默认值，且表单值为None时，需要在"Meta.exclude"添加该字段不进行验证。
'''
class SetNone:
    def __init__(self, *args, **kwargs):
        self.filter = kwargs.get('filter', [])              # 不进行转换的字段名

    def __call__(self, fun):
        self.fun = fun
        def wrap(*args, **kwargs):
            if kwargs.get('data'):
                self.set(kwargs['data'])
            return fun(*args, **kwargs)
        return wrap

    '''
    将字典中空字符串值转None
    :dic 字典
    '''
    def set(self, dic):
        for k,v in dic.items():
            if v == '' and (k not in self.filter):
                dic[k] = None

'''
模型字段动态过滤
使用示例:
    class DetailSerializer(ModelFieldFilter, serializers.ModelSerializer):
        pass
        
    ModelSerializer(objs, many=True, context={'fields': ['dictText']})
'''
class ModelFieldFilter():
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 从 context 中获取字段配置
        if fields := self.context.get('fields'):
            allowed = set(fields)
            existing = set(self.fields)
            # 移除不在 allowed 中的字段
            for field_name in existing - allowed:
                self.fields.pop(field_name, None)
        
        # 如果指定了 exclude，则移除这些字段
        if exclude := self.context.get('exclude'):
            excluded = set(exclude)
            for field_name in excluded:
                self.fields.pop(field_name, None)